package com.dianping.memcache;

import java.util.Date;
import java.util.Map;
import java.util.Set;

@SuppressWarnings("rawtypes")
public class CacheSizes {

	public static int sizeOfReference() {
		return 4;
	}

	
	public static int sizeOfObject(Object obj) {
		if (obj == null)
			return 4;
		if (obj instanceof Cacheable)
			return ((Cacheable) obj).getCachedSize();
		if (obj instanceof String)
			return sizeOfString((String) obj);
		if (obj instanceof Integer)
			return sizeOfInt();
		if (obj instanceof Long)
			return sizeOfLong();
		if (obj instanceof Character)
			return sizeOfChar();
		if (obj instanceof Boolean)
			return sizeOfBoolean();
		if (obj instanceof Date)
			return sizeOfDate();
		if (obj instanceof Iterable)
			return sizeOfIterable((Iterable) obj);
		if (obj instanceof Map)
			return sizeOfMap((Map) obj);
		return 4;
	}

	public static int sizeOfString(String string) {
		if (string == null) {
			return 0;
		}
		return 4 + string.length() * 2;
	}

	public static int sizeOfInt() {
		return 4;
	}

	public static int sizeOfChar() {
		return 2;
	}

	public static int sizeOfBoolean() {
		return 1;
	}

	public static int sizeOfLong() {
		return 8;
	}

	public static int sizeOfDouble() {
		return 8;
	}

	public static int sizeOfDate() {
		return 12;
	}

	@SuppressWarnings("unchecked")
	public static int sizeOfMap(Map map) {
		if (map == null) {
			return 0;
		}
		// Base map object -- should be something around this size.
		int size = 36;
		for (Map.Entry e : ((Set<Map.Entry>) map.entrySet())) {
			size += sizeOfObject(e.getKey());
			size += sizeOfObject(e.getValue());
		}
		return size;
	}

	public static int sizeOfIterable(Iterable itr) {
		if (itr == null) {
			return 0;
		}
		// Base list object (approximate)
		int size = 36;
		// Add in size of each value
		for (Object o : itr) {
			size += sizeOfObject(o);
		}
		return size;
	}
}